
/*    This file is part of the Managarm operating system.
 *   Copyright (C) 2007, 2008, 2009  Alexander van der Grinten
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

package org.managarm.jmanacclib.frontend.korona;

import java.util.Stack;
import org.managarm.jmanacclib.core.CclibException;
import org.managarm.jmanacclib.core.CclibUnit;

public class KorStream {
	private final KorScanner scanner;
	private final Stack<KorToken> stack = new Stack<KorToken>();
	private KorToken lastToken;
	
	public KorStream(KorScanner scanner) {
		this.scanner = scanner;
	}
	
	/* ------------------ low level token related functions -----------------*/
	public boolean endReached() {
		if(stack.empty() == false)
			return false;
		return scanner.endReached();
	}
	
	public KorToken peekToken() throws CclibException {
		if(stack.empty() == false)
			return stack.peek();
		if(endReached())
			throw new CclibException("Unexpected end of stream",
					getLastUnit(), getLastLine());
		final KorToken token = scanner.fetch();
		stack.push(token);
		return token;
	}
	
	public void consume() {
		lastToken = stack.pop();
	}
	
	public int getCurrentType() throws CclibException {
		return peekToken().type;
	}
	
	public String getCurrentString() throws CclibException {
		return peekToken().string;
	}
	
	// returns the current line
	// returns the last line if the end of the stream is reached
	public int getLastLine() throws CclibException {
		if(endReached())
			return lastToken.line;
		return peekToken().line;
	}

	// returns the current unit
	// returns the last unit if the end of the stream is reached
	public CclibUnit getLastUnit() throws CclibException {
		if(endReached())
			return lastToken.unit;
		return peekToken().unit;
	}
	
	/* ------------------ high level token related functions -----------------*/
	public void assertType(int type) throws CclibException {
		if(getCurrentType() != type)
			throw tokenError(KorToken.typeString(type) + " token");
	}
	
	public void assertToken(int type, String string) throws CclibException {
		assertType(type);
		if(getCurrentString().equals(string) == false)
			throw tokenError(KorToken.typeString(type)
					+ " token '" + string + "'");
		return;
	}
	
	public String forceType(int type) throws CclibException {
		assertType(type);
		final String string = getCurrentString();
		consume();
		return string;
	}
	
	public void forceToken(int type, String string) throws CclibException {
		assertToken(type, string);
		consume();
	}
	
	public boolean typeEquals(int type) throws CclibException {
		return getCurrentType() == type;
	}
	
	public boolean stringEquals(String value) throws CclibException {
		return getCurrentString().equals(value);
	}
	
	public boolean tokenEquals(int type, String string) throws CclibException {
		return typeEquals(type) && stringEquals(string);
	}
	
	public CclibException tokenError(String expected) throws CclibException {
		return new CclibException("Scan error: Unexpected "
				+ KorToken.typeString(getCurrentType()) + " token '"
				+ getCurrentString() + "' expected " + expected,
				getLastUnit(), getLastLine());
	}
}
